package jdmx.framework.common.serialization;

import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import jdmx.framework.common.annotations.EntityField;
import jdmx.library.da.Entity;
import jdmx.library.helpers.TypeHelper;
import jdmx.library.utils.LexicalFactory;

import org.apache.commons.beanutils.PropertyUtils;
import org.jdom.Attribute;
import org.jdom.Element;

public class XmlSerializerForEntity implements XmlSerializer {

	@Override
	public Element serialize(Object envelopeItem, String elementName) {
		Entity entity = (Entity) envelopeItem;
		if (entity == null) return null;
		Boolean includeEntityInfo = true; 
		if (elementName == null) elementName = "Entity";
		
		String entityName = TypeHelper.getObjectClassName(entity);
		String entityPackageName = TypeHelper.getObjectPackageName(entity);
		
		
		Element xmlEntity = new Element(elementName);
		if (includeEntityInfo) {
			xmlEntity.setAttribute(new Attribute("type", "Entity"));
			xmlEntity.setAttribute(new Attribute("entityName", entityName));
			xmlEntity.setAttribute(new Attribute("entityNamespace", entityPackageName));
		}
		
		PropertyDescriptor[] props = PropertyUtils.getPropertyDescriptors(entity);
		for (PropertyDescriptor propertyDescriptor : props) {
			/*
			 * Citeste numele proprietatii
			 */
			if (!(propertyDescriptor.getReadMethod().isAnnotationPresent(EntityField.class))) continue;
			String propertyName = propertyDescriptor.getName();
			
			/*
			 * Daca proprietatea e de tip Entity atunci 
			 * apeleaza recursiv metoda serialize
			 */
			Class<?> propertyTypeClass = propertyDescriptor.getPropertyType();
			if (Entity.class.isAssignableFrom(propertyTypeClass)) {
				Entity innerEntityBean = null;
				try {
					innerEntityBean = ((Entity) propertyDescriptor.getReadMethod().invoke(entity));
				} catch (IllegalArgumentException e) {
				} catch (IllegalAccessException e) {
				} catch (InvocationTargetException e) {
				}
				if (innerEntityBean != null) {
					Element xmlInnerEntityBean = serialize(innerEntityBean, propertyName);
					xmlEntity.addContent(xmlInnerEntityBean);
				}
				continue;
			}
			
			/*
			 * Daca proprietatea nu este de tip EntityBean 
			 * atunci compune elementul XML
			 */
			Object propertyValue = null;
			try {
				propertyValue = PropertyUtils.getProperty(entity, propertyName);
			} catch (IllegalAccessException e1) {
			} catch (InvocationTargetException e1) {
			} catch (NoSuchMethodException e1) {
			}
			if (propertyValue != null) {
				Element xmlProperty = new Element(propertyName);
				xmlProperty.setAttribute(new Attribute("type", ""));
				xmlProperty.setText(propertyValue.toString());
				xmlEntity.addContent(xmlProperty);
			}
		}
		
		/*
		 * Intoarce elementul xml compus
		 */
		return xmlEntity;
	}

	@Override
	public Entity deserialize(Element element) {
		String entityName = element.getAttributeValue("entityName");
		String entityPackageName = element.getAttributeValue("entityPackageName");
		LexicalFactory entityFactory = new LexicalFactory(Entity.class, "", "");		
		Entity entity = (Entity) entityFactory.createInstance(entityName, entityPackageName);
		@SuppressWarnings("unchecked") 
		List<Element> xmlChildren = element.getContent();
		for (Element xmlChild : xmlChildren) {
			String propertyName = xmlChild.getName();
			String propertyType = xmlChild.getAttributeValue("type");
			if (propertyType == "Entity") {
				Entity childEntity = (Entity) deserialize(xmlChild);
				try {
					PropertyUtils.setProperty(entity, propertyName, childEntity);
				} catch (IllegalAccessException e) {
				} catch (InvocationTargetException e) {
				} catch (NoSuchMethodException e) {
				}
				continue;
			}
			Object propertyValue = xmlChild.getText();
			try {
					PropertyUtils.setProperty(entity, propertyName, propertyValue);
			} catch (IllegalAccessException e) {
			} catch (InvocationTargetException e) {
			} catch (NoSuchMethodException e) {
			}
		}
		return entity;
	}
	
}
